/**
 * 	 ALFA player
 *
 *	@author: Bartosz Herman
 *	@author: Michał Kamiński
 *	@author: Michał Mela
 *	@author: Łukasz Michalski
 *
 **/
#include <stdbool.h>
#include "mcu_regs.h"
#include "type.h"
#include "uart.h"
#include "stdio.h"
#include "timer32.h"
#include "timer16.h"
#include "gpio.h"
#include "oled.h"
#include "i2c.h"
#include "joystick.h"
#include "rgb.h"
#include "diskio.h"
#include "ff.h"
#include "ssp.h"
#include "rotary.h"
#include "pca9532.h"
#include "light.h"

typedef enum {
	CENTER, LEFT, RIGHT, UP, DOWN, NONE
} direction;
typedef enum {
	PLAYER, ALARM, SETTINGS, SETTING_EDIT, MENU, EXIT, CARD_PROBLEM
} status;
static uint8_t buf[10]; // Buffer used for writing text to OLED
status PLAYER_STATUS = MENU;
status PLAYER_OLD_STATUS = PLAYER;
int menu_selected_item = 0;
int menu_max_item = 3;

int settings_selected_item = 0;
int settings_max_item = 2;
bool setting_selected = false;

//true is up and false down
bool light_alarm_option = true;
int light_alarm_value = 1000;
int light_alarm_max = 4000;
int light_alarm_step = 100;

//current volume. By default half of max vol.
int volume = 5;

int joy_center = 0;
const int VOLUME_MAX = 8; //indicates max volume
const int BYTES_PER_SECOND = 8000; //indicates bytes per second
const int F_BATCH_SIZE = 2048; //size of batch load form SD card
//file buffer
unsigned char header_buffer[44]; //44 bytes of file description
unsigned char sound_buffer1[2048]; //buffer of played song
unsigned char sound_buffer2[2048]; //buffer of played song

bool current_buffer = true; // Current buffer number
//flags
uint16_t MUST_READ_BUFFER = 1; // Must read buffer
bool play = false; //Indicates if music is played. Change by btn. Uses in play section

bool nextSong = true; //Indicates if load nextSong. Change by joy. In first run load first song.
bool prevSong = false; // Indicates if load prevSong.
DSTATUS cardStatus = STA_NOINIT;
DSTATUS cardStatus_old = STA_NOINIT;

// Variables to load fat;
FATFS fatFS[1];
FRESULT res;
DIR dir;
FIL file;
uint32_t fPointRead = 0;
FILINFO fInfo;

//pointer of current play byte;
uint32_t cnt = 0;

// curent song.
int currentFile = 0;

//uint16_t VIZ_DELAY = 0;                            	   // Delay for amplitude visualization

/**
 * int to String conversion for OLED visualisation
 * @param value - integer value to conversion
 * @param pBuf - output buffer
 * @param len - length of the buffer
 * @param base - number system used in number representation
 * @return void
 **/
static void intToString(int value, uint8_t* pBuf, uint32_t len, uint32_t base) {
	static const char* pAscii = "0123456789abcdefghijklmnopqrstuvwxyz";
	int pos = 0;
	int tmpValue = value;
	// check the buffer and length of the buffer
	if (pBuf == NULL || len < 2) {
		return;
	}
	// check the base of the number
	if (base < 2 || base > 36) {
		return;
	}
	// check value of the number and set the sign
	if (value < 0) {
		tmpValue = -tmpValue;
		value = -value;
		pBuf[pos++] = '-';
	}
	// count amount of the numbers
	do {
		pos++;
		tmpValue /= base;
	} while (tmpValue > 0);
	// check the position
	if (pos > len) {
		return;
	}
	// write end of the buffer
	pBuf[pos] = '\0';
	// convert values to ascii
	do {
		pBuf[--pos] = pAscii[value % base];
		value /= base;
	} while (value > 0);

	return;
}

/**
 * Clean OLED with animation
 * @param f - first color (foreground)
 * @param b - second color (background)
 * @param speed - speed of the animation
 * @return void
 **/
void cleanAnimation(oled_color_t f, oled_color_t b, uint32_t speed) {
	int y = 0;
	// clear screen with the specified background color
	oled_clearScreen(b);
	// draw 64 bars with small delay after every bar
	for (y = 1; y < 65; y++) {
		oled_fillRect(0, y - 1, 95, y, f);
		delay32Ms(0, speed);
	}
}

/**
 * Show start message
 * @param void
 * @return void
 **/
void writeStartMessage() {
	//clear OLED
	oled_clearScreen(OLED_COLOR_BLACK);
	// make an animation
	cleanAnimation(OLED_COLOR_WHITE, OLED_COLOR_BLACK, 3);
	cleanAnimation(OLED_COLOR_BLACK, OLED_COLOR_WHITE, 3);
	// show the title of the application
	oled_putString(0, 32, (uint8_t*) "ALFA Player 1.0", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	// wait 3 seconds
	delay32Ms(0, 3000);
	// make an animation
	cleanAnimation(OLED_COLOR_WHITE, OLED_COLOR_BLACK, 5);
}

void writePlayerView() {
	oled_circle(11, 28, 9, OLED_COLOR_WHITE);
	oled_putString(2, 43, (uint8_t*) "VOL:", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	//oled_putString(2, 54, (uint8_t*) "VIZ:", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeStatus() {
	if (play) {
		oled_putString(7, 25, (uint8_t*) "|>", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	} else {
		oled_putString(7, 25, (uint8_t*) "||", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	}
}

void writeSongName(uint8_t* songName) {
	oled_fillRect(27, 25, 95, 35, OLED_COLOR_BLACK);
	oled_putString(27, 25, songName, OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeVolume() {
	oled_fillRect(25, 42, 25 + 8 * volume, 50, OLED_COLOR_WHITE);
	oled_fillRect(25 + 8 * volume, 42, 95, 50, OLED_COLOR_BLACK);
}

void writeSelection(int selection) {
	oled_fillRect(6, 22, 18, 54, OLED_COLOR_BLACK);
	oled_putString(6, 24 + selection * 8, (uint8_t*) ">>", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeMenu() {
	oled_putString(20, 24, (uint8_t*) "PLAYER", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	oled_putString(20, 32, (uint8_t*) "LIGHT ALARM", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	oled_putString(20, 40, (uint8_t*) "SETTINGS", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	oled_putString(20, 48, (uint8_t*) "EXIT", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeSettings() {
	oled_putString(20, 24, (uint8_t*) "VOLUME", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	oled_putString(20, 32, (uint8_t*) "ALARM VALUE", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
	oled_putString(20, 40, (uint8_t*) "ALARM OPTION", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeSetting(uint8_t* value) {
	oled_fillRect(2, 32, 90, 40, OLED_COLOR_BLACK);
	oled_putString(2, 32, value, OLED_COLOR_WHITE, OLED_COLOR_BLACK);
}

void writeStatusTitle(uint8_t* title) {
	oled_clearScreen(OLED_COLOR_BLACK);
	oled_fillRect(0, 0, 95, 10, OLED_COLOR_WHITE);
	oled_putString(2, 2, title, OLED_COLOR_BLACK, OLED_COLOR_WHITE);
}

void init_speaker() {

	GPIOSetDir(PORT3, 0, 1);
	GPIOSetDir(PORT3, 1, 1);
	GPIOSetDir(PORT3, 2, 1);

	//enable CT32B1_MAT1
	LPC_IOCON->JTAG_nTRST_PIO1_2 = (LPC_IOCON->JTAG_nTRST_PIO1_2 & ~0x7) | 0x3;
	// LM4811 audio amplifier setup
	GPIOSetValue(PORT3, 0, 0); //LM4811-clk
	GPIOSetValue(PORT3, 1, 0); //LM4811-up/dn
	GPIOSetValue(PORT3, 2, 0); //LM4811-shutdn

	LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10);
	LPC_TMR32B1->TCR = 2; //reset counter
	LPC_TMR32B1->TCR = 0;
	LPC_TMR32B1->PR = 0; //prescaler = 0
	LPC_TMR32B1->MCR = (1 << 10) | (1 << 9); //reset TC on MC3 match
	LPC_TMR32B1->MR3 = 346; //set period     //256+90
	LPC_TMR32B1->MR1 = 173; //set duty cycle
	LPC_TMR32B1->PWMC = 2; //enable PWM on MAT1 output
	LPC_TMR32B1->IR = 0xf;
	LPC_TMR32B1->TCR = 1; //counter enable
}

void init() {
	GPIOInit();
	// initialize I2C in master mode for pca9532
	I2CInit((uint32_t) I2CMASTER, 0);
	init_timer32(0, 10);
	init_timer16(0, 8000);
	SysTick_Config(SystemCoreClock / 100);
	if (!(SysTick->CTRL & (1 << SysTick_CTRL_CLKSOURCE_Msk))) {
		LPC_SYSCON->SYSTICKCLKDIV = 0x08;
	}
	init_speaker();
	SSPInit();
	oled_init();
	light_init();
	light_enable();
	light_setRange(LIGHT_RANGE_4000);
	joystick_init();
	rotary_init();
}

/**
 * Initialize SD card.
 * @param void
 * @return int - state of the SD card (1 - error, 0 - OK)
 **/
void initialize_sd() {
	cardStatus_old = cardStatus;
	cardStatus = disk_initialize(0);
	if ((cardStatus & STA_NODISK || cardStatus & STA_NOINIT) && PLAYER_STATUS != CARD_PROBLEM) {
		PLAYER_STATUS = CARD_PROBLEM;
	}
}

/**
 * Systick interrupt handler used for disk operations
 * Checking MMC card
 * @param void
 * @return void
 **/
void SysTick_Handler(void) {
	disk_timerproc();
	cardStatus_old = cardStatus;
	cardStatus = disk_status(0);
	if (((cardStatus & STA_NODISK) || (cardStatus & STA_NOINIT)) && PLAYER_STATUS != CARD_PROBLEM) {
		PLAYER_STATUS = CARD_PROBLEM;
	} else if ((!(cardStatus & STA_NODISK) && !(cardStatus & STA_NOINIT)) && PLAYER_STATUS == CARD_PROBLEM) {
		PLAYER_STATUS = MENU;
	}
}

/**
 * Get joystick direction
 * @param void
 * @return direcion - joystick direction
 **/
direction get_joystick_direction() {
	uint8_t joystick_data;
	// read the joystick state
	joystick_data = joystick_read();
	// compare the joystick state with predefined DOWN state
	if (joystick_data & JOYSTICK_CENTER) {
		delay32Ms(0, 200);
		joy_center++;
		return CENTER;
	} else {
		joy_center = 0;
	}
	if ((joystick_data & JOYSTICK_DOWN) != 0) {
		// Delay is needed (in other case too many actions are counted)
		delay32Ms(0, 200);
		// return the direction
		return DOWN;
	}
	// compare the joystick state with predefined UP state
	if (joystick_data & JOYSTICK_UP) {
		delay32Ms(0, 200);
		return UP;
	}
	if (joystick_data & JOYSTICK_LEFT) {
		delay32Ms(0, 200);
		return LEFT;
	}
	if (joystick_data & JOYSTICK_RIGHT) {
		delay32Ms(0, 200);
		return RIGHT;
	}
	return NONE;
}

/**
 * Get rotary direction
 * @param void
 * @return direction - rotary direction
 **/
direction get_rotary_direction() {
	uint8_t rotary_data;
	rotary_data = rotary_read();
	if (rotary_data != ROTARY_WAIT) {
		if (rotary_data & ROTARY_RIGHT) {
			return RIGHT;
		} else if (rotary_data & ROTARY_LEFT) {
			return LEFT;
		}
	}
	return NONE;
}

/**
 * Timer16-0 interrupt - used for music playback
 * @param void
 * @return void
 **/
extern void TIMER16_0_IRQHandler() {
	// get one byte from buffer and put it to MR1 register in timer32-1 driving the PWM
	LPC_TMR32B1->MR1 = ((current_buffer ? sound_buffer1[cnt] : sound_buffer2[cnt])/ VOLUME_MAX * volume) + 90;
	 // wait for the moment when interrupt on the MR3 match is released - not needed
	while (!(LPC_TMR32B1->IR & 0x8));
	// clear the interrupt flag
	LPC_TMR32B1->IR = 0xf;
	// increase the number of the byte to read
	cnt++;
	//VIZ_DELAY++;
	// at end of the buffer
	if (cnt == F_BATCH_SIZE) {
		// reset byte counter
		cnt = 0;
		// change the buffer
		current_buffer = (current_buffer == 0) ? 1 : 0;
		// set flag - program needs to read next 2kB of audio data
		MUST_READ_BUFFER = 1;
	}
	// interrupt finished
	LPC_TMR16B0->IR = 1;
	return;
}

int main(void) {

	init();
	initialize_sd();
	writeStartMessage();

	direction joy_dir = NONE;
	direction rotary_dir = NONE;
	while (1) {
		//get joystick position with our special function
		joy_dir = get_joystick_direction();
		//check player status
		if (PLAYER_STATUS == MENU) {
			//check is this is first time we are here
			if (PLAYER_OLD_STATUS != MENU) {
				//write title on oled
				writeStatusTitle((uint8_t*) "MENU");
				//write menu on oled
				writeMenu();
				//write selection on oled
				writeSelection(menu_selected_item);
				//wait 200 ms (user must have this additional time)
				delay32Ms(0, 200);
				//change old player status
				PLAYER_OLD_STATUS = MENU;
			} else {
				int old_selection = menu_selected_item;
				//check if joystick is up
				if (joy_dir == UP) {
					menu_selected_item--;
				}
				//check if joystick is down
				if (joy_dir == DOWN) {
					menu_selected_item++;
				}
				//valid selection number
				//auto return function
				if (menu_selected_item > menu_max_item) {
					menu_selected_item = 0;
				}
				if (menu_selected_item < 0) {
					menu_selected_item = menu_max_item;
				}
				//write selection arrows if selection has change
				if (menu_selected_item != old_selection) {
					writeSelection(menu_selected_item);
				}
				//change player status if joystick was pressed or right
				if (joy_dir == RIGHT) {
					if (menu_selected_item == 0) {
						PLAYER_STATUS = PLAYER;
					} else if (menu_selected_item == 1) {
						PLAYER_STATUS = ALARM;
					} else if (menu_selected_item == 2) {
						PLAYER_STATUS = SETTINGS;
					} else if (menu_selected_item == 3) {
						PLAYER_STATUS = EXIT;
					}
				}
			}
		} else if (PLAYER_STATUS == ALARM) {
			if (PLAYER_OLD_STATUS != ALARM) {
				//write title on oled
				writeStatusTitle((uint8_t*) "LIGHT ALARM");
				oled_putString(2, 20, (uint8_t*) "Alarm set: ", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				oled_putString(2, 30, (uint8_t*) "Option: ", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				oled_putString(44, 30, (uint8_t*) (light_alarm_option ? "LIGHTER" : "DARKER"), OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				oled_putString(2, 40, (uint8_t*) "Cur.value: ", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				intToString(light_alarm_value, buf, 10, 10);
				oled_putString(64, 20, buf, OLED_COLOR_WHITE, OLED_COLOR_BLACK);
				PLAYER_OLD_STATUS = ALARM;
			}
			uint32_t lux = light_read();
			oled_fillRect(64, 40, 90, 46, OLED_COLOR_BLACK);
			intToString(lux, buf, 10, 10);
			oled_putString(64, 40, buf, OLED_COLOR_WHITE, OLED_COLOR_BLACK);
			delay32Ms(0, 500);
			if ((light_alarm_option && lux > light_alarm_value) || (!light_alarm_option && lux < light_alarm_value)) {
				PLAYER_STATUS = PLAYER;
				play = true;
			}
			if (joy_dir == CENTER) {
				if (joy_center > 1) {
					PLAYER_STATUS = MENU;
					joy_center = 0;
				}
			}
		} else if (PLAYER_STATUS == SETTING_EDIT) {
			if (PLAYER_OLD_STATUS != SETTING_EDIT) {
				if (settings_selected_item == 0) {
					writeStatusTitle((uint8_t*) "VOLUME");
					intToString(volume, buf, 10, 10);
					writeSetting((uint8_t*) buf);
				} else if (settings_selected_item == 1) {
					writeStatusTitle((uint8_t*) "ALARM VALUE");
					oled_putString(2, 44, (uint8_t*) "Cur.value: ", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
					intToString(light_alarm_value, buf, 10, 10);
					writeSetting((uint8_t*) buf);
				} else if (settings_selected_item == 2) {
					writeStatusTitle((uint8_t*) "ALARM OPTION");
					writeSetting((uint8_t*) (light_alarm_option ? "LIGHTER" : "DARKER"));
				}
				delay32Ms(0, 200);
				PLAYER_OLD_STATUS = SETTING_EDIT;
			}
			if (settings_selected_item == 0) {
				rotary_dir = get_rotary_direction();
				int old_volume = volume;
				if ((joy_dir == UP || rotary_dir == RIGHT) && volume < VOLUME_MAX) {
					volume++;
				}
				if ((joy_dir == DOWN || rotary_dir == LEFT) && volume > 0) {
					volume--;
				}
				if (old_volume != volume) {
					intToString(volume, buf, 10, 10);
					writeSetting((uint8_t*) buf);
				}
			} else if (settings_selected_item == 1) {
				int old_light_alarm_value = light_alarm_value;
				if (joy_dir == UP && light_alarm_value < light_alarm_max - light_alarm_step) {
					light_alarm_value += light_alarm_step;
				}
				if (joy_dir == DOWN && light_alarm_value > light_alarm_step) {
					light_alarm_value -= light_alarm_step;
				}
				if (old_light_alarm_value != light_alarm_value) {
					intToString(light_alarm_value, buf, 10, 10);
					writeSetting((uint8_t*) buf);
				}
				oled_fillRect(64, 44, 90, 52, OLED_COLOR_BLACK);
				intToString(light_read(), buf, 10, 10);
				oled_putString(64, 44, buf, OLED_COLOR_WHITE, OLED_COLOR_BLACK);
			} else if (settings_selected_item == 2) {
				bool old_light_alarm_option = light_alarm_option;
				if (joy_dir == UP) {
					light_alarm_option = !light_alarm_option;
				}
				if (joy_dir == DOWN) {
					light_alarm_option = !light_alarm_option;
				}
				if (old_light_alarm_option != light_alarm_option) {
					writeSetting((uint8_t*) (light_alarm_option ? "LIGHTER" : "DARKER"));
				}
			}
			if (joy_dir == CENTER) {
				if (joy_center > 1) {
					PLAYER_STATUS = SETTINGS;
					joy_center = 0;
				}
			}
		} else if (PLAYER_STATUS == SETTINGS) {
			if (PLAYER_OLD_STATUS != SETTINGS) {
				//write title on oled
				writeStatusTitle((uint8_t*) "SETTINGS");
				writeSettings();
				writeSelection(settings_selected_item);
				delay32Ms(0, 200);
				PLAYER_OLD_STATUS = SETTINGS;
			} else {
				int old_selection = settings_selected_item;
				//check if joystick is up
				if (joy_dir == UP) {
					settings_selected_item--;
				}
				//check if joystick is down
				if (joy_dir == DOWN) {
					settings_selected_item++;
				}
				//valid selection number
				//auto return function
				if (settings_selected_item > settings_max_item) {
					settings_selected_item = 0;
				}
				if (settings_selected_item < 0) {
					settings_selected_item = settings_max_item;
				}
				//write selection arrows if selection has change
				if (settings_selected_item != old_selection) {
					writeSelection(settings_selected_item);
				}
				//change player status if joystick was pressed or right
				if (joy_dir == RIGHT) {
					PLAYER_STATUS = SETTING_EDIT;
				}
			}
			if (joy_dir == CENTER) {
				if (joy_center > 1) {
					PLAYER_STATUS = MENU;
					joy_center = 0;
				}
			}
		} else if (PLAYER_STATUS == PLAYER) {
			if (PLAYER_OLD_STATUS != PLAYER) {
				//write title on oled
				writeStatusTitle((uint8_t*) "PLAYER");
				writePlayerView();
				writeStatus();
				writeVolume();
				if (!play) {
					disable_timer16(0);
				} else {
					enable_timer16(0);
				}
				if (fInfo.fsize != 0) {
					writeSongName((uint8_t*) fInfo.fname);
				}
				PLAYER_OLD_STATUS = PLAYER;
				res = f_mount(0, &fatFS[0]);
				res = f_opendir(&dir, "/");
			}

			// change of playing song
			if (nextSong || prevSong) {
				if (nextSong) {
					currentFile++;
				} else {
					currentFile = ((currentFile - 1) < 0) ? (0) : (currentFile - 1);
				}

				//clear sd data
				uint32_t fPointRead = 0;
				res = f_opendir(&dir, "/");

				int i = 0;
				for (i = 0; i < currentFile; i++) {
					res = f_readdir(&dir, &fInfo);
					if ((res != FR_OK) || !fInfo.fname[0]) {
						currentFile = 0;
						break;
					}
				}
				// open file and check heder data if format is OK - should be RIFF____WAVE
				res = f_open(&file, (XCHAR*) fInfo.fname, FA_READ);
				res = f_read(&file, header_buffer, 44, &fPointRead);

				if (fPointRead > 12 && header_buffer[0] == 'R' && header_buffer[1] == 'I' && header_buffer[2] == 'F' && header_buffer[3] == 'F' && header_buffer[8] == 'W' && header_buffer[9] == 'A'
						&& header_buffer[10] == 'V' && header_buffer[11] == 'E') {
					nextSong = false;
					prevSong = false;
					writeSongName((uint8_t*) fInfo.fname);
				}
			}
			while (MUST_READ_BUFFER != 0) {
				// if present buffer is the first buffer
				if (current_buffer) {
					pca9532_setLeds(255, 0);
					// Read a chunk of 2048 bytes to the second buffer
					res = f_read(&file, sound_buffer2, F_BATCH_SIZE, &fPointRead);
					// if present buffer is the second buffer
				} else {
					pca9532_setLeds(65280, 0);
					// Read a chunk of 2048 bytes to the first buffer
					res = f_read(&file, sound_buffer1, F_BATCH_SIZE, &fPointRead);
				}
				// disable all diodes
				pca9532_setLeds(0, 65535);
				// clear the flag
				MUST_READ_BUFFER--;

				if ((res != FR_OK) || fPointRead == 0) {
					nextSong = true;
					break;
				}
				// Start playback from the beginning of the buffer
				cnt = 0;
			}
			while (MUST_READ_BUFFER == 0 && !nextSong && !prevSong) {
				rotary_dir = get_rotary_direction();
				joy_dir = get_joystick_direction();
				if (rotary_dir != NONE) {
					int oldVolume = volume;
					if (rotary_dir == RIGHT && (volume < VOLUME_MAX)) {
						volume++;
					} else if (rotary_dir == LEFT && (volume > 0)) {
						volume--;
					}
					if (oldVolume != volume) {
						writeVolume();
					}
				}

				// handling of joy - prevSong, nextSong cnt++--
				if (joy_dir == UP) {
					nextSong = true;
					MUST_READ_BUFFER = 1;
					break;
				}
				if (joy_dir == DOWN) {
					prevSong = true;
					MUST_READ_BUFFER = 1;
					break;
				}
				if (joy_dir == CENTER) {
					if (joy_center > 1) {
						PLAYER_STATUS = MENU;
						disable_timer16(0);
						play = false;
						joy_center = 0;
						break;
					} else {
						play = !play;
						if (!play) {
							disable_timer16(0);
						} else {
							enable_timer16(0);
						}
					}
					writeStatus();
					delay32Ms(0, 200);
				}
				if (joy_dir == RIGHT) {
					MUST_READ_BUFFER = 10;
				}
				//if (VIZ_DELAY == 4096) {
					//uint16_t new_value = ((current_buffer ? sound_buffer1[cnt] : sound_buffer2[cnt]) >> 1)+25;
					//oled_fillRect(25, 54, new_value, 61, OLED_COLOR_WHITE);
					//oled_fillRect(new_value, 54, 95, 61, OLED_COLOR_BLACK);
					//VIZ_DELAY = 0;
				//}

			}
		} else if (PLAYER_STATUS == CARD_PROBLEM) {
			if (PLAYER_OLD_STATUS != CARD_PROBLEM || cardStatus_old != cardStatus) {
				oled_clearScreen(OLED_COLOR_BLACK);
				writeStatusTitle((uint8_t*) "ERROR");
				if (cardStatus & STA_NOINIT && !(cardStatus & STA_NODISK)) {
					oled_putString(0, 16, (uint8_t*) "SD/MMC ERROR", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
					disable_timer16(0);
					play = false;
					initialize_sd();
				}
				if (cardStatus & STA_NODISK) {
					oled_putString(0, 16, (uint8_t*) "NO SD/MMC DISK", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
					disable_timer16(0);
					play = false;
				}
				PLAYER_OLD_STATUS = CARD_PROBLEM;
			}
		} else if (PLAYER_STATUS == EXIT) {
			break;
		} else {
			break;
		}
	}
	disable_timer16(0);
	cleanAnimation(OLED_COLOR_WHITE, OLED_COLOR_BLACK, 3);
	cleanAnimation(OLED_COLOR_BLACK, OLED_COLOR_WHITE, 3);
	return 0;
}
